#region (c) 2014 Nguyễn, M. Hải - All rights reserved
/*
BLADE VIEW ENGINE

The MIT License (MIT)
Copyright (c) 2014 Nguyễn, M. Hải

Permission is hereby granted, free of charge, to any person obtaining a copy of this 
software and associated documentation files (the "Software"), to deal in the Software 
without restriction, including without limitation the rights to use, copy, modify, merge
, publish, distribute, sublicense, and/or sell copies of the Software, and to permit 
persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or
 substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE 
FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
DEALINGS IN THE SOFTWARE.
*/
#endregion

#region Record of Change
//             							CHANGE HISTORY
// -------------------------------------------------------------------------------------
// |   DATE    | DEVELOPER  | DESCRIPTION                                              |
// -------------------------------------------------------------------------------------
// | 14-Apr-13 | HaiNM      | First creation.                                          |
// -------------------------------------------------------------------------------------
//
#endregion

#region Record of Audit
//             							REVIEW HISTORY
// -------------------------------------------------------------------------------------
// |   DATE    | REVIEWER   | NOTES                                                    |
// -------------------------------------------------------------------------------------
// -------------------------------------------------------------------------------------
//
#endregion

#region Using directives
using System;
using System.IO;
using System.Drawing;
using System.Windows.Forms;
using System.ComponentModel;

using Thn;
using Thn.IO;
using Thn.Web;
using Thn.Web.Mvc;
using Thn.Web.Blade;
#endregion

namespace Demo
{
    /// <summary>
    /// 
    /// </summary>
#if DEBUG 
    public
#else
    public
#endif 
    partial class fmMain : Form
    {
        #region Fields
        WebServer mServer;
        string mRootPath;

        //MvcModule mMvcModule;
        BladeModule mMvcModule;
        #endregion

        #region Properties
        #endregion

        #region UI Events processing

        #region btnGenerateCode_Click
        private void btnGenerateCode_Click(object sender, EventArgs e)
        {
            /*
             * The BLADE basically works as followed:
             * + From a text template, generate codes
             * + From codes, generate executable assembly
             * + Invoke that assembly.
             * 
             * In this example, we'll see how the first step (text -> codes) is done.
             * 
             */

            string input = @"Hello there, the time now is @DateTime.Now";
            var generator = new BladeCodeGenerator();
            txtResult.Text = generator.Generate(input);
        }
        #endregion

        #region btnManualRender_Click
        private void btnManualRender_Click(object sender, EventArgs e)
        {
            /*
             * In this example, we'll use a view renderer to execute
             * a view template with the view is generated from a .cshtml file
             * on disk.
             */

            //the renderer responsible for rendering view
            BladeViewRenderer renderer = new BladeViewRenderer();

            //the path translator is responsible for resolving the actual location
            //on disk of the view files
            UriToLocalPathTranslator translator = new UriToLocalPathTranslator();
            translator.Root = "Views";
            renderer.PathTranslator = translator;

            //declare the view we will be rendering
            RenderArgs args = new RenderArgs();
            args.ViewName = "0_HelloWorld";//this maps to file Views\0_HelloWorld.cshtml
            
            //create a writer responsible for writing text. In this case, we'll render to memory
            Stream memStream = new MemoryStream();
            IByteStream stream = new SystemByteStream(memStream);
            IContextWriter writer = new ContextWriter(stream);
            args.Writer = writer;

            //assign a data model for binding to the view. We don't have any special
            //model this time, so we'll just pass in this very form to demonstrate
            //the technique only
            args.Model = this;

            //ask the renderer to render the view
            ((IViewRenderer)renderer).Render(args);

            //read back the rendered view as text
            stream.Seek(0, SeekFrom.Begin);
            TextReader reader = new StreamReader(memStream);
            txtResult.Text = reader.ReadToEnd();
        }
        #endregion

        #region btnStart_Click
        private void btnStart_Click(object sender, EventArgs e)
        {
            StartServer();
        }
        #endregion

        #region btnStop_Click
        private void btnStop_Click(object sender, EventArgs e)
        {
            StopServer();
        }
        #endregion

        #endregion

        #region Server Events processing

        #region mServer_Started
        void mServer_Started(object sender, EventArgs e)
        {
            mIsStarting = false;
            UpdateUIBasedOnStatus();
        }
        #endregion

        #region mServer_StartFailed
        void mServer_StartFailed(object sender, Exception error)
        {
            mIsStarting = false;
            UpdateUIBasedOnStatus();

            this.RunOnUI((a) =>
            {
                Log.Warning("Could not start server");
                Log.Error(error);
            });
        }
        #endregion

        #region mServer_Stopped
        void mServer_Stopped(object sender, Exception error)
        {
            UpdateUIBasedOnStatus();
        }
        #endregion

        #endregion

        #region Update UI based on status
        bool mIsStarting = false;

        void UpdateUIBasedOnStatus()
        {
            this.RunOnUI((a) =>
            {
                if (mIsStarting)
                {
                    #region Server is starting
                    btnStart.Enabled = false;
                    btnStop.Enabled = false;
                    lblStatus.Text = "Starting...";
                    lblStatus.ForeColor = Color.Yellow;
                    #endregion
                }
                else if (mServer != null && mServer.IsListening)
                {
                    #region Server has started
                    btnStart.Enabled = false;
                    btnStop.Enabled = true;
                    lblStatus.Text = "Running...";
                    lblStatus.ForeColor = Color.GreenYellow;
                    #endregion
                }
                else
                {
                    #region Server has stopped
                    btnStart.Enabled = true;
                    btnStop.Enabled = false;
                    lblStatus.Text = "Stopped";
                    lblStatus.ForeColor = Color.Red;
                    #endregion
                }
            });
        }
        #endregion

        #region Intialize Server
        void InitializeServer()
        {
            if (mServer == null)
            {
                mServer = new WebServer();
                mServer.Root = mRootPath;
                mServer.Stopped += mServer_Stopped;
                mServer.StartFailed += mServer_StartFailed;
                mServer.Started += mServer_Started;

                //add mvc module to server
                //var mvc = new MvcModule();
                var mvc = new BladeModule();
                mServer.Modules.Add(mvc);

                //Note: we can use the plain-vanilla MvcModule to initialize our web server.
                //However, we won't be able to browse .cshtml file because the vanilla
                //MVC does not know what .cshtml is.
                //The BladeModule does support that.
                //For most of our examples, we don't need the BladeModule. Except for
                //the views inside Views\Blade folder

                //save a reference to this module so that we can register
                //our controllers after the server started.
                mMvcModule = mvc;
            }
            #region Defensive tracing
            else
            {
                //already initialized
            }
            #endregion
        }
        #endregion

        #region Start Server
        void StartServer()
        {
            InitializeServer();

            if (!mServer.IsListening)
            {
                mServer.Port = txtPort.Text.Parse<int>();
                mIsStarting = true;
                UpdateUIBasedOnStatus();
                mServer.Start();

                //register our sample controllers
                mMvcModule.ControllerManager.RegisterController(new HomeController());
                mMvcModule.ControllerManager.RegisterController(new SimpleController());
                mMvcModule.ControllerManager.RegisterController(new BladeController());
                mMvcModule.ControllerManager.RegisterController(new PartialController());
            }
            #region Defensive tracing
            else
            {
                //already started
            }
            #endregion
        }
        #endregion

        #region Stop Server
        void StopServer()
        {
            if (mServer != null && mServer.IsListening)
            {
                mServer.Stop();
            }
            #region Defensive tracing
            else
            {
                //not running, no need to stop
            }
            #endregion
        }
        #endregion

        #region On Load
        /// <summary>
        /// Initialize this form when form is loaded.
        /// </summary>
        protected override void OnLoad(EventArgs e)
        {
            if (!DesignMode)
            {
#if DEBUG
                Log.Logger.SetPriorityFilter(LogPriority.Debug);
#endif
                UpdateUIBasedOnStatus();

                mRootPath = @"Views\";

                //make sure Blade is available
                Services.Register(typeof(IViewRenderer), typeof(BladeViewRenderer));

                //auto-start
                StartServer();
            }
            #region Defensive tracing
            else
            {
                //don't do anything at design-time
            }
            #endregion

            //let my ancestor process its own logic
            base.OnLoad(e);
        }
        #endregion

        #region fmMain_FormClosing
        private void fmMain_FormClosing(object sender, FormClosingEventArgs e)
        {
            StopServer();
        }
        #endregion
        
        #region Constructors
        /// <summary>
        /// Default constructor.
        /// </summary>
        public fmMain() 
        {
            InitializeComponent();
        }
        #endregion

    }
}
